library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity pipeid is
	generic
	(
		DATA_WIDTH	: natural  :=	32;
		IMM_WIDTH	: natural  :=	16;
		REG_WIDTH	: natural  :=	5;
		ALUC_WIDTH	: natural  :=	5
	);


	port
	(
		-- Input ports
		-- to control unit
		mwreg : in std_logic;
		mm2reg : in std_logic;
		mwmem : in std_logic;
		mdesr : in std_logic_vector(REG_WIDTH-1 downto 0);
		ewreg : in std_logic;
		em2reg : in std_logic;
		edesr : in std_logic_vector(REG_WIDTH-1 downto 0);
		-- from pipeir
		pcf : in std_logic_vector(DATA_WIDTH-1 downto 0);
		inst : in std_logic_vector(DATA_WIDTH-1 downto 0);
		irqmask : in std_logic;
		-- from pipewreg
		wrfnd : in std_logic_vector(REG_WIDTH-1 downto 0);
		-- from pipewb
		wrfdi : in std_logic_vector(DATA_WIDTH-1 downto 0);
		-- from pipeexe
		ealu : in std_logic_vector(DATA_WIDTH-1 downto 0);
		-- from pipemreg
		malu : in std_logic_vector(DATA_WIDTH-1 downto 0);
		-- from pipemem
		mmo : in std_logic_vector(DATA_WIDTH-1 downto 0);
		dcacheok : in std_logic;
		-- from pipemwreg
		wwreg : in std_logic;
		-- from outside
		clk : in std_logic;
		clrn : in std_logic;
		
		-- Output ports
		-- to pipeif
		fwda_out : out std_logic_vector(1 downto 0);
		fwdb_out : out std_logic_vector(1 downto 0);
		bpc : out std_logic_vector(DATA_WIDTH-1 downto 0);
		branch : out std_logic;
		jpatch : out std_logic;
		iret : out std_logic;
		-- wpcir
		nostall : out std_logic;
		cen : out std_logic;
		-- to pipedereg
		wreg : out std_logic;
		m2reg : out std_logic;
		wmem : out std_logic;
		aluc : out std_logic_vector(ALUC_WIDTH-1 downto 0);
		aluimm : out std_logic;
		a : out std_logic_vector(DATA_WIDTH-1 downto 0);
		b : out std_logic_vector(DATA_WIDTH-1 downto 0);
		imm : out std_logic_vector(DATA_WIDTH-1 downto 0);
		desr : out std_logic_vector(REG_WIDTH-1 downto 0);
		shift : out std_logic		
	);
end pipeid;

architecture rtl_pipeid of pipeid is
component cu
	port
	(
		-- Input ports
		instr	: in  std_logic_vector(31 downto 0);
		irqmask : in std_logic;
		-- from pipeid
		rsrtequ	: in std_logic;	-- if rs = rt
		-- Pipeline reg state
		mwreg : in std_logic;
		mm2reg : in std_logic;
		mwmem : in std_logic;
		mdesr : in std_logic_vector(REG_WIDTH-1 downto 0);
		ewreg : in std_logic;
		em2reg : in std_logic;
		edesr : in std_logic_vector(REG_WIDTH-1 downto 0);
		-- Cache ok
		dcacheok : in std_logic;
		
		-- Output ports
		cen 	: out std_logic;
		fwda	: out std_logic_vector(1 downto 0);
		fwdb	: out std_logic_vector(1 downto 0);
		wpcir	: out std_logic; -- write instruction register
		jump	: out std_logic;
		branch	: out std_logic;
		jpatch	: out std_logic;
		iret	: out std_logic;
		writereg	: out std_logic; -- wreg
		regdes	: out std_logic; -- regrt
		writemem	: out std_logic; -- wmem
		memtoreg	: out std_logic; -- m2reg
		shift	: out std_logic;
		aluop	: out std_logic_vector (4 downto 0);
		alusrcb	: out std_logic;-- aluimm
		se	: out std_logic -- sext
	);
end component;
component regfile
	port
	(
		-- Input ports
		n0	: in  std_logic_vector(REG_WIDTH-1 downto 0);
		n1	: in  std_logic_vector(REG_WIDTH-1 downto 0);
		nd	: in  std_logic_vector(REG_WIDTH-1 downto 0);
		di	: in  std_logic_vector(DATA_WIDTH-1 downto 0);
		ce	: in  std_logic;
		clk : in  std_logic;
		clrn: in  std_logic;		
		-- Output ports
		result0	: out std_logic_vector(DATA_WIDTH-1 downto 0);
		result1	: out std_logic_vector(DATA_WIDTH-1 downto 0)
	);
end component;
component lpm_mux32x4
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		data2x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		data3x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		sel		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		result		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
	);
end component;
component lpm_mux32
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
	);
end component;
component lpm_mux5
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (4 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (4 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (4 DOWNTO 0)
	);
end component;
component signextend
	port
	(
		-- Input ports
		immediate	: in  std_logic_vector(IMM_WIDTH-1 downto 0);
		se	: in  std_logic;		
		-- Output ports
		extendimm	: out std_logic_vector(DATA_WIDTH-1 downto 0)
	);
end component;
signal regclk,regdes,se,jump,rsrtequ : std_logic;
signal fwda,fwdb : std_logic_vector(1 downto 0);
signal da,db,branch_addr,result0,result1,address,extimm : std_logic_vector(DATA_WIDTH-1 downto 0);
--shared variable branch_addr : std_logic_vector(DATA_WIDTH-1 downto 0);

begin
	controlunit: cu port map(
		instr => inst,
		irqmask => irqmask,
		rsrtequ => rsrtequ,
		mwreg => mwreg,
		mm2reg => mm2reg,
		mwmem => mwmem,
		mdesr => mdesr,
		ewreg => ewreg,
		em2reg => em2reg,
		edesr => edesr,
		dcacheok => dcacheok,
		-- output
		cen => cen,
		fwda => fwda,
		fwdb => fwdb,
		wpcir => nostall,
		jump => jump,
		branch => branch,
		jpatch => jpatch,
		iret => iret,
		writereg => wreg,
		regdes => regdes,
		writemem => wmem,
		memtoreg => m2reg,
		shift => shift,
		aluop => aluc,
		alusrcb => aluimm,
		se => se
	);

-- Process branch and jump
	address <= pcf(31 downto 28) & inst(25 downto 0) & pcf(1 downto 0);
	process (inst)
		variable shift_extimm : std_logic_vector(DATA_WIDTH-1 downto 0):= extimm(29 downto 0) & "00";
	begin
		branch_addr <=  shift_extimm+pcf;
	end process;
	jump_mux: lpm_mux32 port map(
		data0x => branch_addr,
		data1x => address,
		sel => jump,
		result => bpc
	);
	
-- Process regfiles
	regclk <= not clk;
	regs: regfile port map(
		n0 => inst(25 downto 21), -- rs
		n1 => inst(20 downto 16), -- rt
		nd => wrfnd,
		di => wrfdi,
		ce => wwreg,
		clk => regclk,
		clrn => clrn,
		result0 => result0,
		result1 => result1
	);
	
	fwda_mux: lpm_mux32x4 port map(
		data0x => result0,
		data1x => ealu,
		data2x => malu,
		data3x => mmo,
		sel => fwda,
		result => da
	);
	a <= da;
	
	fwdb_mux: lpm_mux32x4 port map(
		data0x => result1,
		data1x => ealu,
		data2x => malu,
		data3x => mmo,
		sel => fwdb,
		result => db
	);
	b <= db;
	
-- Process if rs = rt
	rsrtequ <= '1' when da = db else
			   '0';
-- Process Sign extension
	se_comp: signextend port map(
		immediate => inst(15 downto 0),
		se => se,
		extendimm => extimm
	);
	imm <= extimm;
	
-- To desreg
	desr_mux: lpm_mux5 port map(
		data1x => inst(15 downto 11), --desr = rd
		data0x => inst(20 downto 16), --desr = rt
		sel => regdes,
		result => desr
	);
	
	fwda_out <= fwda;
	fwdb_out <= fwdb;
end rtl_pipeid;

